import {computed, designPage, reactive, toArray, useRefs} from "@peryl/react-compose";
import {AiChatBox, Button, ButtonGroup, PageCard, PageCardTitle, Tree} from "plain-design";
import './ai-stream-json-page.scss';
import {deepcopy} from "@peryl/utils/deepcopy";
import {throttle} from "@peryl/utils/throttle";
import {createJsonStreamHandler, iJsonStreamHandler} from "./createJsonStreamHandler";

export default designPage(() => {

  const { refs, onRef } = useRefs({ tree: Tree });

  const state = reactive({
    jsonData: {} as any,
    stateExpandKeys: [] as string[],
    receiving: false,
  });

  const cascadeInfo = computed((): { cascadeData: iCascadeData[], expandKeys: string[] } => {
    const expandKeys: string[] = [];
    const iterate = (obj: any, parentKey = ''): iCascadeData[] => {
      if (obj == null) {return [];}
      if (Array.isArray(obj)) {
        return (obj as any[]).map((item, index) => {
          const key = `${parentKey}.${index}`;
          expandKeys.push(key);
          return {
            key,
            label: String(index),
            children: item == null ? [] : iterate(item, key)
          };
        });
      } else {
        return Object.entries(obj).map(([k, v]) => {
          const typeOfValue = typeof v;
          const key = `${parentKey}.${k}`;
          expandKeys.push(key);
          if (typeOfValue === 'object') {
            return {
              key,
              label: k,
              children: iterate(v)
            };
          } else {
            return {
              key,
              label: v == null ? k : `${k}: ${v}`,
            };
          }
        });
      }
    };
    const cascadeData = iterate(state.jsonData);
    return { cascadeData, expandKeys };
  });

  const systemPrompt = `
你是一名专业的json数据生成专家，专门生成测试所需要的json数据；你需要根据用户的描述生成一份json数据；
注意的是，你必须以点表示法返回这个json数据，不需要任何说明解释，你只需要返回这段数据；点表示法如下所示：

- 比如要生成的json数据为 [{"id":"xxx", "products":[{"id":"product_id_01","name":"product_a"},{"id":"product_id_02","name":"product_b"}]}]
- 那么要生成的点表示法数据如下所示：

0.id=xxx
0.products.0.id=product_id_01
0.products.0.name=product_a
0.products.1.id=product_id_02
0.products.1.name=product_b
  `;

  const userContent = `
如下所示，订单数据类型为iOrder：
interface iOrder {
  id: string,           // 订单id
  createdAt: string,    // 订单创建时间
  products: iProduct[], // 订单商品
}

interface iProduct {
  id: string,           // 商品id
  name: string,         // 商品名称
  price: number,        // 商品价格
}
每条订单应该有1到3条商品，帮我生成不少于3条订单数据
  `;

  let _fullText = '';
  let jsonStreamHandler: iJsonStreamHandler;
  const handleReceive = ({ chunkText }: { fullText?: string, chunkText?: string }) => {
    _fullText += chunkText;
    if (!chunkText?.trim().length) {return;}
    _fullText = jsonStreamHandler.handleFullText(_fullText).list.join('\n');
    state.jsonData = deepcopy(jsonStreamHandler.getData());
    throttleExpand();
  };

  const beforeSendUserContent = async () => {
    jsonStreamHandler = createJsonStreamHandler();
    _fullText = '';
    state.receiving = true;
    state.stateExpandKeys = [];
    state.jsonData = null;
  };
  const handleFinish = () => {
    state.receiving = false;
    console.log(jsonStreamHandler.getData());
  };

  const throttleExpand = throttle(() => {
    refs.tree?.methods.expandAll();
    refs.tree?.refs.list?.refs.scroll?.methods.scrollEnd();
  }, 500);

  return () => (
    <PageCard full className="ai-stream-json-page page-card-horizontal">
      <PageCardTitle title="流式解析JSON数据">
        <ButtonGroup>
          <Button label="全部展开" onClick={() => refs.tree?.methods.expandAll()}/>
          <Button label="全部收起" onClick={() => refs.tree?.methods.collapseAll()}/>
        </ButtonGroup>
      </PageCardTitle>
      <div className="page-card-horizontal-body">
        <div className="page-card-horizontal-content" style={{ flex: 1 }}>
          <div className="page-card-horizontal-content-inner">
            <Tree
              ref={onRef.tree}
              virtual
              keyField="key"
              labelField="label"
              childrenField="children"
              data={cascadeInfo.value.cascadeData}
              expand={state.receiving ? cascadeInfo.value.expandKeys : state.stateExpandKeys}
              onUpdateExpand={val => state.stateExpandKeys = val ?? []}
            />
          </div>
        </div>
        <div className="page-card-horizontal-content" style={{ width: '400px' }}>
          <div className="page-card-horizontal-content-inner">
            <AiChatBox
              fitHeight
              systemContent={systemPrompt}
              modelValue={userContent}
              handleReceive={handleReceive}
              handleMessage={handleFinish}
              beforeSendUserContent={beforeSendUserContent}
            />
          </div>
        </div>
      </div>
    </PageCard>
  );
});

interface iCascadeData {
  label: string,
  children?: iCascadeData[],
}
